import datetime
import os
import random
import sys
from flask import Blueprint, request, current_app
from flask import session
from werkzeug.utils import secure_filename
from common.exceptions import NotFound, NotFoundException, AuthorizationFailed
from model.article import ArticleModel
from model.team import TeamSpaceModel
from util.auth_validate import auth_validate
from util.db import Cursor
from flask_restx import reqparse
import uuid
from util.login_validate import login_validate
from util.tid_miker import tid_maker
from util.time_transform import time_trans

app_article = Blueprint(name="app_article", import_name=__name__, url_prefix='/api/article')


class ArticleMenu:

    @staticmethod
    @app_article.route('/articleMenu', methods=['GET'])
    def get_article_menu():
        parser = reqparse.RequestParser()
        parser.add_argument('articleId', type=str, help='文章ID', trim=True)
        args = parser.parse_args(strict=True)
        article_id = args.get('articleId')
        article_list = ArticleModel.get_article_child(article_id=article_id)
        return {"code": 0, "errMsg": "成功", "data": article_list}, 200

    @staticmethod
    @app_article.route('/articleMenuInit', methods=['GET'])
    def get_article_menu_init():
        parser = reqparse.RequestParser()
        parser.add_argument('articleId', type=str, help='文章ID', trim=True)
        parser.add_argument('bookId', type=str, help='知识库ID', trim=True)
        parser.add_argument('id', type=str, help='文章主键ID', trim=True)
        args = parser.parse_args(strict=True)
        book_id = args.get('bookId')
        article_id = args.get('articleId')
        article_list = ArticleModel.get_article_child_digui(book_id=book_id, article_id=article_id)
        return {"code": 0, "errMsg": "成功", "data": article_list}, 200


class ArticleContent:

    @staticmethod
    @app_article.route('/upload', methods=['POST'])
    @login_validate
    def post_upload_file():
        user_id = str(session.get('user_id'))
        file = request.files['file[]']
        file_name = uuid.uuid4().hex
        file_ext = os.path.basename(secure_filename(file.filename)).split('.')[-1]
        date_time = datetime.datetime.now().date().strftime('%Y_%m_%d')
        directory = os.path.join(current_app.config['UPLOAD_FOLDER'], date_time, user_id)
        if not os.path.exists(directory):
            os.makedirs(directory)
        file_path = os.path.join(directory, file_name + '.' + file_ext)
        file.save(file_path)
        host = 'http://192.168.31.178:5005' if sys.platform == 'win32' else 'https://www.yugongcoding.com'
        if file_ext.lower().strip() in ['png', 'jpg', 'gif', 'jpeg']:
            media_type = 'image'
        elif file_ext.lower().strip() in ['mp4', 'ts']:
            media_type = 'video'
        elif file_ext.lower().strip() in ['mp3', 'wav']:
            media_type = 'audio'
        else:
            media_type = 'file'
        return {
            "msg": "",
            "code": 0,
            "data": {
                "errorFiles": [],
                "successMap": {
                    'media_type': media_type,
                    'url': host + current_app.config['UPLOAD_PREFIX'] + '/'.join([date_time, user_id, file_name + '.' + file_ext])
                }
            }
        }

    @staticmethod
    @app_article.route('/articleContent', methods=['POST'])
    @login_validate
    def post_article_content():
        parser = reqparse.RequestParser()
        parser.add_argument('name', type=str, help='文章名称', nullable=False, required=True, trim=True)
        parser.add_argument('articleId', type=str, help='当前节点ID', trim=True)
        parser.add_argument('fatherId', type=str, help='父节点ID', trim=True)
        parser.add_argument('flag', type=int, help='插入位置标记，节点前后还是子节点')
        parser.add_argument('position', type=str, help='插入子节点位置，开头或结尾', trim=True, required=False)
        parser.add_argument('isRoot', type=bool, help='是否在根节点插入')
        parser.add_argument('auth', type=int, help='可见范围', required=True)
        parser.add_argument('teamId', type=int, help='团队ID', required=True)
        parser.add_argument('bookId', type=int, help='知识库ID', required=True)
        parser.add_argument('category', type=str, help='文章分类标签', required=False)

        args = parser.parse_args(strict=True)
        auth = args.get('auth')
        article_id = args.get('articleId')
        father_id = args.get('fatherId')
        name = args.get('name')
        flag = int(args.get('flag'))
        is_root = args.get('isRoot')
        user_id = session.get('user_id')
        team_id = args.get('teamId')
        book_id = args.get('bookId')
        category = args.get('category')
        position = args.get('position')

        create_time = datetime.datetime.now()
        new_article_id = tid_maker()
        # 鉴权
        team_role = TeamSpaceModel.get_team_role(id=team_id, id_type='team')
        if not team_role or team_role == 'reader':
            raise AuthorizationFailed()
        read_time = 0
        content = ''

        add_id = None

        with Cursor() as cursor:
            if flag == 0:
                add_id = article_id
                sort_num = 0
                if position == 'end':
                    sql = """select max(sort) as sort from yugong_article where father_id=%s for update"""
                    cursor.execute(sql, [article_id])
                    sort = cursor.fetchall()
                    if sort[0]['sort'] is not None:
                        sort_num = int(sort[0]['sort']) + 1
                if position == 'start':
                    sql = """select min(sort) as sort from yugong_article where father_id=%s for update"""
                    cursor.execute(sql, [article_id])
                    sort = cursor.fetchall()
                    if sort[0]['sort'] is not None:
                        sort_num = int(sort[0]['sort']) - 1
                sql = """insert into yugong_article (article_id, father_id, name, sort, auth, 
                create_time, create_person, update_time, read_time, team_id, book_id, content, category) 
                values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
                cursor.execute(sql,
                               [new_article_id, article_id, name, sort_num, auth, create_time, user_id, create_time, read_time, team_id, book_id, content, category])
            elif flag == -1:
                add_id = father_id
                sql = """select sort from yugong_article where article_id=%s for update"""
                cursor.execute(sql, [article_id])
                sort = cursor.fetchall()
                sort_num = int(sort[0]['sort']) - 1
                sql = """update yugong_article set sort=sort-1 where father_id=%s and sort<%s"""
                cursor.execute(sql, [father_id, sort[0]['sort']])
                sql = """insert into yugong_article (article_id, father_id, name, sort, auth, 
                create_time, create_person, update_time, read_time, team_id, book_id, content, category) 
                values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
                cursor.execute(sql,
                               [new_article_id, father_id, name, sort_num, auth, create_time, user_id, create_time, read_time, team_id, book_id, content, category])
            elif flag == 1:
                add_id = father_id
                sql = """select sort from yugong_article where article_id=%s for update"""
                cursor.execute(sql, [article_id])
                sort = cursor.fetchall()
                sort_num = int(sort[0]['sort']) + 1
                sql = """update yugong_article set sort=sort+1 where father_id=%s and sort>%s"""
                cursor.execute(sql, [father_id, sort[0]['sort']])
                sql = """insert into yugong_article (article_id, father_id, name, sort,
                 auth, create_time, create_person, update_time, read_time, team_id, book_id, content, category) 
                 values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
                cursor.execute(sql,
                               [new_article_id, father_id, name, sort_num, auth, create_time, user_id, create_time, read_time, team_id, book_id, content, category])
            this_id = cursor.lastrowid
            sql = """update yugong_article set child_num=child_num+1 where article_id=%s"""
            cursor.execute(sql, [add_id])
            sql = """insert into yugong_statistic (resource_id, create_time) values (%s, %s)"""
            cursor.execute(sql, [this_id, create_time])
        article_info = ArticleModel.get_article_info(this_id)
        return {"code": 0, "errMsg": "添加成功", "data": article_info}, 200

    @staticmethod
    @app_article.route('/articleContent', methods=['PATCH'])
    @login_validate
    def patch_article_content():
        parser = reqparse.RequestParser()
        parser.add_argument('content', type=str, help='文本内容', trim=True)
        parser.add_argument('name', type=str, help='文章名称', trim=True)
        parser.add_argument('auth', type=int, help='文本内容', trim=True)
        parser.add_argument('id', type=int, help='文章主键ID', trim=True)
        parser.add_argument('category', type=str, help='标签分类', trim=True)

        args = parser.parse_args(strict=True)
        concat_sql = []
        concat_params = []
        user_id = session.get('user_id')
        id = args.get('id')
        fields = []
        content = args.get('content')
        # 鉴权
        team_role = TeamSpaceModel.get_team_role(id=id, id_type='article')
        if not team_role or team_role == 'reader':
            raise AuthorizationFailed()
        for field in ['name', 'auth', 'category']:
            if args.get(field) is not None:
                concat_sql.append(field + '=%s')
                concat_params.append(args.get(field))
                fields.append(field)
        concat_params.append(id)
        with Cursor() as cursor:
            # 更新文章内容
            if content is not None:
                word_count = len(content)
                read_time = word_count / 275 * 60
                sql = """update yugong_article set word_count=%s,content=%s, read_time=%s where id=%s"""
                cursor.execute(sql, [word_count, content, read_time, id])
            # 更新文章属性
            else:
                sql = """update yugong_article set {} where id=%s""".format(','.join(concat_sql))
                cursor.execute(sql, concat_params)
            if content is not None:
                sql = """select {} from yugong_article where id=%s""".format(','.join(['word_count', 'content', 'read_time']))
            else:
                sql = """select {} from yugong_article where id=%s""".format(','.join(fields))
            cursor.execute(sql, [id])
            res = cursor.fetchall()[0]
            if res.get('read_time') is not None:
                res['read_time'] = str(datetime.timedelta(seconds=res['read_time']))
        return {"code": 0, "errMsg": "保存成功", "data": res}, 200

    @staticmethod
    @app_article.route('/articleContent', methods=['GET'])
    def get_article_content():
        parser = reqparse.RequestParser()
        parser.add_argument('articleId', type=str, help='此节点ID', trim=True)
        parser.add_argument('id', type=str, help='主键ID', trim=True)
        args = parser.parse_args(strict=True)
        id = args.get('id')
        res = ArticleModel.get_article_content(id=id)
        with Cursor() as cursor:
            sql = """update yugong_statistic set views=views+1 where resource_id=%s"""
            cursor.execute(sql, [id])
        return {"code": 0, "errMsg": "成功", "data": res}, 200

    @staticmethod
    @app_article.route('/articleContent', methods=['DELETE'])
    @login_validate
    def delete_article_content():
        parser = reqparse.RequestParser()
        parser.add_argument('articleId', type=str, help='此节点ID', trim=True)
        parser.add_argument('id', type=int, help='文章主键ID', trim=True)

        args = parser.parse_args(strict=True)
        articleId = args.get('articleId')
        id = args.get('id')
        user_id = session.get('user_id')
        # 鉴权
        team_role = TeamSpaceModel.get_team_role(id=id, id_type='article')
        if team_role != 'admin':
            raise AuthorizationFailed()

        def find_all_children(article_id):
            """递归删除"""
            with Cursor() as cursor:
                sql = """delete from yugong_article where article_id=%s"""
                cursor.execute(sql, [article_id])
                sql = """select article_id from yugong_article where father_id=%s"""
                cursor.execute(sql, [article_id])
                article_id_list = cursor.fetchall()
            for item in article_id_list:
                find_all_children(item.get('article_id'))

        with Cursor() as cursor:
            sql = """select father_id from yugong_article where article_id=%s"""
            cursor.execute(sql, [articleId])
            father_id = cursor.fetchall()[0]['father_id']
            sql = """update yugong_article set child_num = child_num - 1 where article_id=%s"""
            cursor.execute(sql, [father_id])
        find_all_children(articleId)
        # 更新父亲节点子节点数量
        return {"code": 0, "errMsg": "删除成功", "data": None}, 200

    @staticmethod
    @app_article.route('/statistic', methods=['GET'])
    def get_article_statistic():
        parser = reqparse.RequestParser()
        parser.add_argument('id', type=int, help='此节点ID', trim=True)

        args = parser.parse_args(strict=True)
        id = args.get('id')
        user_id = session.get('user_id')
        if session.get('login_status'):
            result = {'is_like': False, 'is_collect': False}
            with Cursor() as cursor:
                sql = """select views, likes, collects from  yugong_statistic where resource_id=%s"""
                cursor.execute(sql, [id])
                data_s = cursor.fetchall()

                sql = """select is_like, is_collect from yugong_like_collect where resource_id=%s and user_id=%s"""
                cursor.execute(sql, [id, user_id])
                data_l = cursor.fetchall()
            if data_s:
                result.update(data_s[0])
            if data_l:
                result['is_like'] = bool(data_l[0]['is_like'])
                result['is_collect'] = bool(data_l[0]['is_collect'])
        else:
            result = {}
            with Cursor() as cursor:
                sql = """select views, likes, collects from  yugong_statistic where resource_id=%s"""
                cursor.execute(sql, [id])
                data_s = cursor.fetchall()
                if data_s:
                    result.update(data_s[0])
        return {"code": 0, "errMsg": "成功", "data": result}, 200

    @staticmethod
    @app_article.route('/statistic', methods=['PATCH'])
    @login_validate
    def patch_article_statistic():
        parser = reqparse.RequestParser()
        parser.add_argument('id', type=int, help='此节点ID', trim=True)
        parser.add_argument('flag', type=str, help='此节点ID', trim=True)
        parser.add_argument('operation', type=int, help='此节点ID', trim=True)

        args = parser.parse_args(strict=True)
        id = args.get('id')
        flag = args.get('flag')
        operation = args.get('operation')

        user_id = session.get('user_id')
        create_time = datetime.datetime.now()
        with Cursor() as cursor:
            if flag == 'collect' and operation == -1:
                sql = """insert into yugong_like_collect (user_id, resource_id, is_collect, create_time) values 
                                                    (%s, %s, 0, %s) on duplicate key update is_collect=0"""
                cursor.execute(sql, [user_id, id, create_time])
                sql = """update yugong_statistic set collects=collects-1 where resource_id=%s"""
                cursor.execute(sql, [id])

            if flag == 'collect' and operation == 1:
                sql = """insert into yugong_like_collect (user_id, resource_id, is_collect, create_time) values 
                                    (%s, %s, 1, %s) on duplicate key update is_collect=1"""
                cursor.execute(sql, [user_id, id, create_time])
                sql = """update yugong_statistic set collects=collects+1 where resource_id=%s"""
                cursor.execute(sql, [id])


            if flag == 'like' and operation == -1:
                sql = """insert into yugong_like_collect (user_id, resource_id, is_like, create_time) values 
                                                                    (%s, %s, 0, %s) on duplicate key update is_like=0"""
                cursor.execute(sql, [user_id, id, create_time])
                sql = """update yugong_statistic set likes=likes-1 where resource_id=%s"""
                cursor.execute(sql, [id])

            if flag == 'like' and operation == 1:
                sql = """insert into yugong_like_collect (user_id, resource_id, is_like, create_time) values 
                                                    (%s, %s, 1, %s) on duplicate key update is_like=1"""
                cursor.execute(sql, [user_id, id, create_time])
                sql = """update yugong_statistic set likes=likes+1 where resource_id=%s"""
                cursor.execute(sql, [id])

        return {"code": 0, "errMsg": "成功", "data": None}, 200


class Book:

    @staticmethod
    @app_article.route('/book', methods=['GET'])
    def get_book():
        parser = reqparse.RequestParser()
        parser.add_argument('bookId', type=int, help='知识库ID', trim=True, location='args')
        args = parser.parse_args(strict=True)
        book_id = args.get('bookId')
        book_info = ArticleModel.get_book_info(book_id)
        return {"code": 0, "errMsg": "成功", "data": book_info}, 200

    @staticmethod
    @app_article.route('/book_category', methods=['GET'])
    def get_book_category():
        parser = reqparse.RequestParser()
        parser.add_argument('bookId', type=int, help='知识库ID', trim=True, location='args')
        args = parser.parse_args(strict=True)
        book_id = args.get('bookId')
        book_category = ArticleModel.get_all_book_category(book_id)
        return {"code": 0, "errMsg": "成功", "data": book_category}, 200


class Comment:

    @staticmethod
    @app_article.route('/comment', methods=['PATCH'])
    def patch_comment():
        parser = reqparse.RequestParser()
        parser.add_argument('id', type=int, help='文章主键ID', trim=True, required=True)
        parser.add_argument('operationType', type=str, help='操作类型，点赞|踩', trim=True, required=True)
        parser.add_argument('flag', type=int, help='增加减少点赞', trim=True, required=False)
        args = parser.parse_args(strict=True)
        id = args.get('id')
        operation_type = args.get('operationType')
        flag = args.get('flag')
        create_time = datetime.datetime.now()
        user_id = session.get('user_id')
        with Cursor() as cursor:
            if operation_type == 'like' and flag == 1:
                sql = """select * from yugong_comment_like where resource_id=%s"""
                cursor.execute(sql, [id])
                res = cursor.fetchall()
                if not res:
                    sql = """insert into yugong_comment_like (user_id, resource_id, is_like, create_time) values (%s, %s, 1, %s)"""
                    cursor.execute(sql, [user_id, id, create_time])
                    sql = """update yugong_comment_statistic set likes=likes+1 where id=%s"""
                    cursor.execute(sql, [id])
                else:
                    sql = """update yugong_comment_like set is_like=1, is_unlike=0 where resource_id=%s"""
                    cursor.execute(sql, [id])
                    if res[0].get('is_unlike') == 1:
                        sql = """update yugong_comment_statistic set likes=likes+1, unlikes=unlikes-1 where id=%s"""
                    else:
                        sql = """update yugong_comment_statistic set likes=likes+1 where id=%s"""
                    cursor.execute(sql, [id])

            if operation_type == 'like' and flag == -1:
                sql = """update yugong_comment_like set is_like=0 where resource_id=%s"""
                cursor.execute(sql, [id])

                sql = """update yugong_comment_statistic set likes=likes-1 where id=%s"""
                cursor.execute(sql, [id])

            if operation_type == 'unlike' and flag == 1:
                sql = """select * from yugong_comment_like where resource_id=%s"""
                cursor.execute(sql, [id])
                res = cursor.fetchall()
                if not res:
                    sql = """insert into yugong_comment_like (user_id, resource_id, is_unlike, create_time) values (%s, %s, 1, %s)"""
                    cursor.execute(sql, [user_id, id, create_time])
                    sql = """update yugong_comment_statistic set unlikes=unlikes+1 where id=%s"""
                    cursor.execute(sql, [id])
                else:
                    sql = """update yugong_comment_like set is_like=0, is_unlike=1 where resource_id=%s"""
                    cursor.execute(sql, [id])
                    if res[0].get('is_like') == 1:
                        sql = """update yugong_comment_statistic set likes=likes-1, unlikes=unlikes+1 where id=%s"""
                    else:
                        sql = """update yugong_comment_statistic set unlikes=unlikes+1 where id=%s"""
                    cursor.execute(sql, [id])

            if operation_type == 'unlike' and flag == -1:
                sql = """update yugong_comment_like set is_unlike=0 where resource_id=%s"""
                cursor.execute(sql, [id])

                sql = """update yugong_comment_statistic set unlikes=unlikes-1 where id=%s"""
                cursor.execute(sql, [id])
        return {"code": 0, "errMsg": "成功", "data": None}, 200

    @staticmethod
    @app_article.route('/comment', methods=['GET'])
    def get_comment():
        parser = reqparse.RequestParser()
        parser.add_argument('id', type=int, help='文章主键ID', trim=True, required=True)
        args = parser.parse_args(strict=True)
        id = args.get('id')
        with Cursor() as cursor:
            sql = """select * from (select * from yugong_comment_statistic as a
	LEFT JOIN
	(SELECT avatar, id as u_id, username from yugong_user) as b
	ON a.user_id=b.u_id
	WHERE a.reply_comment_id IS NULL and a.article_id=%s) c

LEFT JOIN
(SELECT resource_id, is_like, is_unlike from yugong_comment_like) as d
ON c.id=d.resource_id
order by create_time desc
                    """
            cursor.execute(sql, [id])
            res = cursor.fetchall()
            for item in res:
                sql = """select * from (select * from yugong_comment_statistic as a
	LEFT JOIN
	(SELECT avatar, id as u_id, username from yugong_user) as b
	ON a.user_id=b.u_id
	WHERE a.first_comment_id=%s) c

LEFT JOIN
(SELECT resource_id, is_like, is_unlike from yugong_comment_like) as d
ON c.id=d.resource_id
order by create_time asc"""
                cursor.execute(sql, [item.get('id'), ])
                children = cursor.fetchall()
                for data in children:
                    data['is_unlike'] = True if data['is_unlike'] == 1 else False
                    data['is_like'] = True if data['is_like'] == 1 else False
                    data['create_time'] = time_trans(datetime.datetime.now(), data['create_time'])
                item['children'] = children
                item['is_unlike'] = True if item['is_unlike'] == 1 else False
                item['is_like'] = True if item['is_like'] == 1 else False
                item['create_time'] = time_trans(datetime.datetime.now(), item['create_time'])
        return {"code": 0, "errMsg": "成功", "data": res}, 200

    @staticmethod
    @app_article.route('/comment', methods=['POST'])
    @login_validate
    def post_comment():
        parser = reqparse.RequestParser()
        parser.add_argument('id', type=int, help='文章ID', trim=True, required=True)
        parser.add_argument('comment', type=str, help='评论内容', trim=True,  required=True)
        parser.add_argument('replyUserId', type=int, help='回复某人', trim=True, required=False)
        parser.add_argument('replyCommentId', type=int, help='回复某条评论', trim=True, required=False)
        parser.add_argument('replyUserName', type=str, help='回复用户名', trim=True, required=False)
        parser.add_argument('firstCommentId', type=int, help='首条评论ID', trim=True, required=False)

        args = parser.parse_args(strict=True)
        article_id = args.get('id')
        comment = args.get('comment')
        reply_user_id = args.get('replyUserId')
        first_comment_id = args.get('firstCommentId')
        reply_user_name = args.get('replyUserName')
        reply_comment_id = args.get('replyCommentId')
        create_time = datetime.datetime.now()
        user_name = session.get('username')
        user_id = session.get('user_id')
        with Cursor() as cursor:
            sql = """insert into yugong_comment_statistic (article_id, comment, user_id, create_time, reply_user_id, reply_comment_id, reply_user_name, first_comment_id, user_name) 
            values (%s, %s, %s, %s, %s, %s, %s, %s, %s)"""
            cursor.execute(sql, [article_id, comment, user_id, create_time, reply_user_id, reply_comment_id, reply_user_name, first_comment_id, user_name])
            this_id = cursor.lastrowid
            sql = """select * from yugong_comment_statistic where id=%s"""
            cursor.execute(sql, [this_id])
            res = cursor.fetchall()
            data = None
            if res:
                data = res[0]
        return {"code": 0, "errMsg": "成功", "data": data}, 200
